# -*- coding: utf-8 -*-
"""
Spyder Editor

This temporary script file is located here:
C:\Users\max\.spyder2\.temp.py
"""
import numpy as np
import random as rd
import math as mat
import time


#################################################
# Retorna se Um valor é solucao 
#
#
##################################33

def Ehsolucao(enta , epsilon):
    if (enta < epsilon): 
        return True
    else: 
        return False 
#################################################
# Retorna se dois valores são iguais
# com uma margem epsilon de erro 
# 0 = falso , 1 = verdadeiro 
#
#
##################################33

def Iguais(a , b, epsilon):
    temp = a-b
    #print " a e b " 
    #print a , b 
    
    situacao=True
    for j in range(0,len(a)):
        #print "tempj"
        #print j 
        #print abs(temp[j]) , epsilon
        if ( abs(temp[j]) > epsilon  ):
            return False
    return situacao


#################################################
# Retorna a distancia euclidiana do vetor de entrada
#
#
##################################33

def disteucli(entb):
    somat=0.0
    for j in range(0,len(entb)):
        somat= somat+ (entb[j]*entb[j]) 
    
    return (np.sqrt(somat))    

#################################################
# Retorna a norma de dois vetores
#
##################################33

def Dist(ent1,posa,ent2,posb):
    tempdb=0.0
    for j in range(0,D):
        tempdb= tempdb+ ((ent1[posa][j]-ent2[posb][j])**2    )
    return (np.sqrt(tempdb))    
#################################################
# Retorna 1 se entrada menor que rho (epsilon) 
# retorna 0 senao 
#
##################################33

def Csi(aa,bb):
    if (aa <= bb):
        return (1.0)    
    else:
        return (0.0)    

#################################################
# Retorna qual valor deve ser selecionado 
# 
#valor  = 0 minimizacao 
# valor  = 1 maximizacao 
# valor = 2 raizes 
##################################33

def criterioselecao(a,b):
#MINIMIZACAO
    if (a<b):#minimizacao
        return True
    else : 
        return False 

#MAXIMIZACAO 
'''
    if (a>b):#maximo
        return True
    else : 
        return False 
'''
#BUSCA DE zeros 
'''
    if ( disteucli(a)< disteucli(b) ):
        return True
    else : 
        return False 
''' 

####################################################
        

####################################3
# mutacao 
# crossover 
# selecao 
####################################
def Mutacao (x,F):
    v= np.zeros([NP,D],float) #criando o vetor vi,G+1
    #print " F = %f" % F      
    for i in range(0,NP): #Pega cada individuo
        r1=0         
        r2=0         
        r3=0
        while (r1==r2) or (r2==r3) or (r1==r3) or (r1==i) or(r2==i) or (r3==i):
            r1 = rd.randrange(0,NP)
            r2 = rd.randrange(0,NP)
            r3 = rd.randrange(0,NP)        
        #print " Valores %d , %d , %d " %(r1,r2,r3)         
        for k in range (0,D):   #cada parametro do individuo
            v[i][k]=(x[r1][k]+F*(x[r3][k]-x[r2][k])) 
            #aqui pode ser dado um tratamento 
            #while (v[i][k] > limvar[i][k]   )           
            if (k==0): 
                while(v[i][k]<limvar[0][0] or v[i][k]>limvar[0][1]):
                        a=np. random.uniform(limvar[k][0],limvar[k][1])   
                        v[i][k]=(limvar[0][0]+F*(limvar[0][1]-a)) 
            if (k==1): 
                while(v[i][k]<limvar[1][0] or v[i][k]>limvar[1][1]):
                         a=np. random.uniform(limvar[k][0],limvar[k][1])   
                         v[i][k]=(limvar[1][0]+F*(limvar[1][1]-a)) 
               

            
            # se o v[i][k] estiver fora dos limites 
            # pode-se quica-lo de volta (bonce-back)
            # ou sortear um numero dentro do intervalo 
            #http://books.google.com.br/books?id=S67vX-KqVqUC&printsec=frontcover&hl=pt-BR&source=gbs_atb#v=onepage&q=out-of&f=false
            # pesquisar por out-of-bounds
    return v;    

def Crossover (x,v,CR):
    
    #li aleatorio de 1 .. D  deve ser mudado em cada k 
    rj =np.zeros

    u= np.zeros([NP,D],float) #criando o vetor ui,G+1
        
    for k in range (0,NP):
        li = rd.randrange(0,D)        
        for j in range(0,D):
            rj=np. random.uniform(0.0,1.0) #sorteia um rj  de 0 .. 1        
            if (rj<=CR) or (j==li):
                u[k][j]=v[k][j]
            else:
                u[k][j]=x[k][j]
    return u

def Selecao (u,x):   
    xsec= np.zeros([NP,D],float) #criando o vetor ui,G+1
    for k in range (0,NP):
            tempf=Funcao(u,k)
            tempf2=Funcao(x,k)
            if (criterioselecao(tempf,tempf2)): # criterio diz se eh max , min ou busca de solucoes 
                for i in range (0,D):
                    xsec[k][i]=u[k][i] 
                arq2.write ("funcao  " +   str(k) + "  " +  str(tempf))  
                arq2.write (" \n ")
            else:
                #print "x"
                for i in range (0,D):
                    xsec[k][i]=x[k][i]
                arq2.write ("funcao  " +  str(k) + "  " +  str(tempf))  
                arq2.write (" \n ")
                    
    return xsec                  


# para remover o grasp , comentar a soma da funcao 
# para sistemas algebricos , elevar cada 
# funcao ao quadrado e somar todas ao grasp
def Funcao (entc,p):
    temp=abs(entc[p][0])+abs(entc[p][1])
    temp2=entc[p][0]**2+entc[p][1]**2    
    f=(-1)*temp*mat.exp(-temp2) 
    
    saida = f + (Grasp(entc,p,epsilon))
   
   #
    #if (f!=saida ):    
    #   print f , saida 
    return (saida)            


#def Funcao (ent,p):
    
       
    #gama =1000.0;
    #Dezao=22.0;
    #beta1=2.0;
    #beta2=2.0; 
    #R=0.995;
    #f= np.zeros([2],float) #criando o vetor ui,G+1    

    # GRASP 
#    quad = 0.0 ;    
#    betaGRASP = 10000;
#    rho = 0.0001;
#    somat = 0.0; 
#    delta = 0.0 ;     
    
    #f[0] = ((1-R)*( (Dezao/(10*(1+beta1))) - ent[p][0])*mat.exp(10*ent[p][0]/(1+(10*ent[p][0]/gama))))-ent[p][0];

    #f[1] = ent[p][0]-(1+beta2)*ent[p][1]+(1-R)*(Dezao/10.0-beta1*ent[p][0]-(1+beta2)*ent[p][1])*mat.exp(10*ent[p][1]/(1.0+10.0*ent[p][1]/gama));
    
    #quad = (f[1]**2 + f[0]**2);
    #quad  = (ent[p][0]+2.0*ent[p][1]-7.0)**2+(2*ent[p][0]+ent[p][1]-5.0)**2;
     
   # for j in range(0,len(solucoes)):
   #     delta = distentrevet(ent,p,solucoes,j);
   #     somat = somat + (np.exp(-delta) * csi(delta,rho));
    
    #return (quad ) #+ betaGRASP*somat )    
    #print norma;
         
#rho precisa de ajuste para garantir uma boa 
# eliminacao da vizinhanca do otimo encontrado 
def Grasp (entrada,pos,epsilon):
    ssoma=0.0;
    beta = 10000.0
    rho = 1.0 
    result = 0.0
    tempr=0.0
    for i in range (0,len(solucoes)):
        tempr = Dist(entrada,pos,solucoes,i)
        #print tempr , entrada[pos] ,solucoes[i] 
        ssoma = ssoma +(np.exp(-tempr)*Csi(tempr,rho)) # se temmp > rho retorna 0 senao retorna 1 
    result = beta*ssoma
    return (result)

   # print encontradas
#    for k in range (0,NP):
#        tempf=Funcao(ent,k)
#        if (tempf<epsilon): # se F(x) é solucao 
#            encontradas=ChecaVetor(solucoes,ent[k],encontradas )
            #print contador  
            #print tempf
#        for i in range (0,D):
            


    


'''#funcao antiga 
    temp=np.zeros
    temp2=np.zeros
    temp=abs(a[p][0])+abs(a[p][1])
    temp2=a[p][0]**2+a[p][1]**2
    f=(-1)*temp*mat.exp(-temp2)
    return (f)            
'''
    

def DE(NP , D, CR, F , maxgen, limvar,epsilon):

    #F = np. random.uniform(0.0,2.0) #criando o F     
    ###########################
    #Gerando a populacao da primeira geracao   
    ###########################
    
    x= np.zeros([NP,D],float)
    xb= np.zeros([NP,D],float)
    tempv= np.zeros([NP,D],float)
    tempu= np.zeros([NP,D],float)
    
      

    #gerando o x 
    for j in range (NP):      
            x[j][0]=np. random.uniform(limvar[0][0],limvar[0][1])        
    
    #gerando o y 
    for j in range (NP):      
            x[j][1]=np. random.uniform(limvar[1][0],limvar[1][1])        
    
    
    # gere quantas dimensoes forem necessarias 
    
    for m in range (max_gen):
    
        ###########################
        #MUTACAO  
        ########b################### 
        tempv = Mutacao(x,F)
    
        ###########################
        #Crossover
        ###########################
        tempu=Crossover (x,tempv,CR)        
    
        ###########################
        #Gerando a populacao inicial da prox iteracao  
        ###########################
        xb=Selecao(tempu,x)
        
        #gravando o xb em x para a prox geracao
        x=xb
        #for j in range (NP):
        #    for i in range(D): 
        #        x[j][i]=xb[j][i]
        #escrevendo no arquivo 
        arq2.write ("Geracao" + str(m)) 
        
        for j in range (NP):
            arq.write ("\n")
            for i in range(D):
                    arq.write ("G%d[%d][%d]= %f " % (m ,j,i, x[j][i] )) 
        arq.write ("\n")             
    posescolha= BuscaSolucao(x);
    return x[posescolha]

# busca no vetor x na ultima populacao o 
# menor ou maior valor ( estabelecido pela funcao criterioselecao)
def BuscaSolucao(entf):
    atual = Funcao(entf,0)
    posescolha = 0
    #print x 
    for j in range (NP): 
        for i in range(D): 
            if (criterioselecao(Funcao(entf,j),atual)):
                atual = Funcao(entf,j)
                posescolha = j 
    return posescolha
    
###############################################3
## Parametros do DE 
##NP = numero de populacoes 
# D = dimensoes do problema 
# CR = Coeficiente de crossover
# F = Coeficiente de mutacao 
# num_sol = numero de solucoes esperadas 
# maxgen = numero maximo de geracoes (unico criterio de parada) ( em otm estocastica nao há convergencia)
# limvar  = limites superiores e inferiores de cada variável de-
# ve ser ajustado antes de rodar a funcao 
# EXEMPLO : 
#limvar[0][0]=0.5;  # x inferior  
#limvar[0][1]=0.8;   # x superior

#limvar[1][0]=-3.6;  # y inferior  
#limvar[1][1]=-3.0;   # y superior 
#################################################33
arq = open('C:\\Users\\max\\Desktop\\ponto.txt','w')
arq2 = open('C:\\Users\\max\\Desktop\\valorfuncao.txt','a')              

# programa principal 
NP= 50 #NP numero de populacoes  
D=2 #numero de dimensoes do problema  
CR = 0.6
F=0.4
max_gen = 100

num_sol=4


solucoes = [] # vetor das solucoes  [0,0] , [0,1] , [1,0] , [1,1] a segunda casa vai até a dimensao do problema   

limvar= np.zeros([D,D],float)

limvar[0][0]=-4;  # x inf 
limvar[0][1]=4;   # x sup
    
limvar[1][0]=-4  # y inf 
limvar[1][1]=4;   # y sup

epsilon = 0.00001;

start = time.clock()
for j in range (num_sol):
    solucao = DE(NP , D, CR, F ,  max_gen, limvar , epsilon )
    print solucao
    solucoes.append(solucao)
#olha a ultima geracao e busca uma solucao. Verifica que a solucao nao jah está 
# presente no vetor de solucoes      

end = time.clock()
arq.close()
arq2.close()    
 
print "Tempo de algoritmo = ", end - start, "seconds"   
        #print "vou printar" 










'''
####################################3
# Checa se o vetor tem valores repetidos
#  verifica se X* jah esta no vetor 
####################################
def ChecaVetor (solucoes,entd,encontradas):
    
    print encontradas 
    if (encontradas==0):
        encontradas = encontradas + 1
        for i in range (0,D):        
            solucoes[0]=entd
        
    else: 
        for i in range (0,encontradas):
            if (Iguais(solucoes[i],entd,0.0000000001)):
                print entd 
                encontradas= encontradas +1
                solucoes[encontradas]=entd
    
    return encontradas    
'''